/*
 * PlanForMethod.java
 * 
 * Copyright 2002 Christoph Csallner and Yannis Smaragdakis.
 */
package edu.gatech.cc.jcrasher.plans;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import edu.gatech.cc.jcrasher.writer.CodeGenFct;

/**
 * PlanForMethod
 *
 * Wraps a method
 * - Manages recursion to params and optional victim instance
 *
 * Automatic Testing: 
 * Crash java classes by passing inconvenient params
 * 
 * Christoph Csallner
 * 2002-06-12 created
 */
public class PlanForMethod implements PlanForFunction {

	/**
	 * Type of instance generated by this plan.
	 */
	private Class<?> returnType = null;
 
	/**
	 * Which plans generate params passed to construct this value
	 * - zero-elem-array --> constructor takes no arguments
	 * - list of params in order to construct value
	 */
	private Plan[] constrParams = null;

	/**
	 * How to instantiate the object on which the method will be instantiated?
	 * - null iff constructor or static method
	 */
	private Plan victim = null;

	/**
	 * Which method has generated this value?
	 */
	private Method conMeth = null;


	/**  
 	 * Constructor
	 * - static method
	 */
	public PlanForMethod (Method pMeth, Plan[] pConstrParams) {
		assert pMeth != null;
		assert pConstrParams != null;
  		
  	returnType = pMeth.getReturnType();
  	conMeth = pMeth;
		constrParams = pConstrParams;
  }

	
	/**  
 	 * Constructor
	 * - non-static method
	 */
	public PlanForMethod (Method pMeth, Plan[] pConstrParams, Plan pVictim) {  			
  	assert pMeth != null;
  	assert pConstrParams != null;
  	assert pVictim != null;
  		
  	returnType = pMeth.getReturnType();
  	conMeth = pMeth;	
		constrParams = pConstrParams;
		victim = pVictim;
  }  



	/**
	 * @return type of instance created by this plan
	 */
	public Class<?> getReturnType() {
		assert returnType != null;
		return returnType;	
	}
	
  
	/**
	 * How to reproduce this value=object?
	 * - Variable or (recursive) constructor-chain for user-output after some
	 *   mehtod-call crashed using this object as param.
	 * - Example: new A(new B(1), null)
	*/
	public String toString(Class<?> testee) {  	
		/* Fully qualified class-name: Enc.Nested */
		String className = CodeGenFct.getName(conMeth.getDeclaringClass(), testee);

		StringBuffer res = new StringBuffer();
		
		/* static meth */
		if (Modifier.isStatic(conMeth.getModifiers()) == true) {
			res.append(className +"." +conMeth.getName() +"(");
		}
		
		else {  // (new Victim()).conMeth(
			if (victim instanceof PlanForConstructor) {
				res.append("(" +victim.toString(testee) +")." +conMeth.getName() +"(");
			}
			else {  // A.b().conMeth()
				res.append(victim.toString(testee) +"." +conMeth.getName() +"(");
			}
		}
	
	
		/* Parameter tail: recurse */
		for (int i=0; i<constrParams.length; i++) {
   			if (i>0) { res.append(", "); }        			//separator		
			res.append(constrParams[i].toString(testee)); //value
		}		
		
		/* return assembeled String */
		res.append(")");	
		return res.toString();
	}  
}

